using UnityEngine;
using System.Collections;

public class CharacterBehaviour : MonoBehaviour
{
	public float hp = 100;
	
	[SerializeField]
	private ExplosionBehaviour explosionDied;
	
	[SerializeField]
	private Transform pivotExplosionDied;
	
	[SerializeField]
	private bool itsPushedOnHit = true;
	
	[SerializeField]
	private bool haveDelayToHits = true;
	
	[SerializeField]
	private float delayToEnableHit = 0;
	private bool enableHit = true;
	
	[SerializeField]
	private ExplosionBehaviour hitEffect;
	[SerializeField]
	private Transform pivotHitEffect;
	
	protected bool onHit = false;
	private bool hitRightToLeft = false;
	private int countChangeColor = 4, currentCountChanges = 0;
	private float timeChangeColor = 0.1f, currentTimeChange = 0;
	private bool changeColor = false;
	private Color originalColor;
	
	[SerializeField]
	private AudioClip dashClip = null, slashClip = null, shotClip = null, jumpClip = null;
	private AudioSource audioSource;
	
	#region Movimentacao
	
	[SerializeField]
	protected DetectorCollider footDetector = null, frontDetector = null, backDetector = null;
	[SerializeField]
	private float speedAxisX = 500;
	protected Vector2 velocity = Vector2.zero;
	
	#endregion Movimentacao;
	
	#region Dash
	
	[SerializeField]
	private ExplosionBehaviour dashEffect;
	
	[SerializeField]
	private Transform pivotHorizontalDashEffect, pivotDownDashEffect = null, pivotUpDashEffect = null;
	
	private bool onDash = false;
	private float timeOnDash = 0.3f, currentTimeOnDash = 0;
	private Vector2 directionDash;
	
	#endregion Dash;
	
	#region Pulo
	
	[SerializeField]
	private bool useGravity = true;
	
	[SerializeField]
	private int jumpCount = 2;
	private int currentJump = 1;
	private bool jump = false;
	
	[SerializeField]
	private float maxHeightOnJump = 200;
	private float currentHeightOnJump = 0;
	
	#endregion Pulo;
	
	#region Tiro
	
	[SerializeField]
	private Transform pivotShot = null, bullet = null;
	[SerializeField]
	private float timeToShotBullet = 0;
	private bool shooting = false;
	
	#endregion Tiro;
	
	#region Melee
	
	[SerializeField]
	private DetectorCollider detectorMelee;
	[SerializeField]
	private Transform pivotSlash = null;
	[SerializeField]
	private ExplosionBehaviour slashSword = null;
	[SerializeField]
	private float timeToCheckHitOnMelee = 0;
	private bool melee = false;
	
	protected bool hitAnEnemy = false;
	
	#endregion Melee;
	
	[SerializeField]
	private GameObject backSpecial;
	
	protected bool specialAir = false;
	[SerializeField]
	private ExplosionBehaviour specialAirEffect;
	private ExplosionBehaviour tempAirEffect;
	[SerializeField]
	private Transform pivotSpecialAir;
	[SerializeField]
	private DetectorCollider detectorSpecialAir;
	private int limitPlaySpecialAirEffect = 2, countSpecialAirEffect = 0;
	
	protected bool specialShot = false;
	[SerializeField]
	private ExplosionBehaviour[] specialShotEffect;
	private ExplosionBehaviour[] tempShotEffect;
	[SerializeField]
	private Transform pivotSpecialShot;
	[SerializeField]
	private DetectorCollider detectorSpecialShot;
	
	[SerializeField]
	private ExplosionBehaviour littleDust = null;
	
	[SerializeField]
	private Transform pivotDust = null;
	private float oldVelocityX = 0;
	
	[SerializeField]
	private int hitShot = 0, hitMelee = 0, hitSpecialAir = 0, hitSpecialShot = 0;
	
	[HideInInspector]
	public int diedAnEnemy = 0;
	
	private bool slowingJump = false;
	
	protected Transform _transform;
	
	[SerializeField]
	protected ManagerAnimationUV animationUV;
	
	protected bool OnGround
	{
		get { return !footDetector.IsFree; }
	}
	
	protected bool OnLastJump
	{
		get{ return(currentJump.Equals(jumpCount)); }
	}
	
	protected bool OnDash
	{
		get { return onDash; }
	}
	
	protected virtual void Awake()
	{
		audioSource = GameObject.Find("_AudioSourceEffects").GetComponent<AudioSource>();
		if(!animationUV)
			animationUV = GetComponentInChildren<ManagerAnimationUV>();
		_transform = transform;
	}
	
	protected virtual void Update() 
	{
		if(onHit)
		{
			HitEffect();
		}
		else
		{
			if(hp > 0 && hp < 99)
			{
				if(footDetector != null)
				{
					GameObject platform = footDetector.GetObjectOfLayer((int)Global.LAYER.MovePlatform);
			
					if(platform)
					{ _transform.parent = platform.transform; }
					else{ _transform.parent = null; }
				}
				
				UpdateAnimations();
				
				UpdateJump();
				
				UpdateDustOnGround();
				
				_transform.Translate(new Vector3(velocity.x * Time.deltaTime, velocity.y, 0));
				velocity = new Vector2(0, velocity.y);
			}
			else
			{
				if(explosionDied != null)
				{
					Instantiate(explosionDied.gameObject, pivotExplosionDied.position, Quaternion.identity);
				}
				
				Destroy(gameObject);
			}
		}
	}
	
	protected void Shot(bool waitFinish)
	{
		if(!waitFinish || !shooting)
		{
			animationUV.Stop();
			
			animationUV.Play("shot");
			
			if(velocity == Vector2.zero)
			{animationUV.Play("shot");}
			else
			{animationUV.Play("shotDash");}
			
			StartCoroutine(WaitToEmitBullet());
			
			shooting = true;
		}
	}
	
	private IEnumerator WaitToEmitBullet()
	{
		yield return new WaitForSeconds(timeToShotBullet);
		
		audioSource.PlayOneShot(shotClip);
		
		GameObject g = (GameObject)Instantiate(bullet.gameObject, pivotShot.position, Quaternion.identity);
		g.GetComponent<BulletBehaviour>().damage = hitShot;
		g.GetComponent<BulletBehaviour>().myCharacter = this;
		if(_transform.localScale.x < 0)
		{g.transform.Rotate(Vector3.forward * 180);}
	}
	
	protected void Melee()
	{
		if(!melee)
		{
			audioSource.PlayOneShot(slashClip);
			
			animationUV.Stop();
			
			animationUV.Play("melee");
			
			GameObject g = (GameObject)Instantiate(slashSword.gameObject, pivotSlash.position, Quaternion.identity);
			
			if(transform.localScale.x < 0)
			{
				g.transform.localScale = new Vector3(-1, g.transform.localScale.y, g.transform.localScale.z);
			}
			
			g.transform.parent = transform;
			
			melee = true;
			
			StartCoroutine(WaitToCheckHitOnMelee());
		}
	}
	
	private IEnumerator WaitToCheckHitOnMelee()
	{
		yield return new WaitForSeconds(timeToCheckHitOnMelee);
		
		//Checar hit
		if(!detectorMelee.IsFree)
		{
			hitAnEnemy = true;
			slowingJump = true;
			StartCoroutine(NormalizeJump());
			
			if(currentJump == jumpCount)
			{
				currentJump = jumpCount -1;
			}
			
			foreach(GameObject g in detectorMelee.GetObjects)
			{
				if(g.GetComponent<CharacterBehaviour>())
				{
					if(g.GetComponent<CharacterBehaviour>().Hit(hitMelee, (_transform.localScale.x < 0), true))
					{
						diedAnEnemy ++;
					}
				}
			}
		}
	}
	
	private IEnumerator NormalizeJump()
	{
		yield return new WaitForSeconds(0.3f);
		
		slowingJump = false;
	}
	
	protected void TryMove(bool toRight)
	{
		if(!onDash)// && (!shooting || footDetector.IsFree))
		{
			if(toRight)
			{
				_transform.localScale = Vector3.one;
			}
			else
			{
				_transform.localScale = new Vector3(-1, 1, 1);
			}
			
			if(frontDetector.IsFree)// && cameraFollower.FinishTween)
			{
				if(toRight)
				{velocity = new Vector2(speedAxisX, velocity.y);}
				else
				{velocity = new Vector2(-speedAxisX, velocity.y);}
			}
		}
	}
	
	protected void TryMove(Vector2 direction)
	{
		if(!onDash)// && (!shooting || footDetector.IsFree))
		{
			if(direction.x > 0)
			{
				_transform.localScale = Vector3.one;
			}
			else if(direction.x < 0)
			{
				_transform.localScale = new Vector3(-1, 1, 1);
			}
			
			if(direction.x != 0)
			{
				if(frontDetector.IsFree)// && cameraFollower.FinishTween)
				{
					velocity = new Vector2(direction.x * speedAxisX, velocity.y);
				}
			}
			
			if(direction.y != 0)
			{
				velocity = new Vector2(velocity.x, direction.y * speedAxisX * Time.deltaTime);
			}
		}
	}
	
	protected void Dash(Vector2 direction)
	{
		if(!shooting || velocity != Vector2.zero)
		{
			directionDash = direction;
			
			GameObject g = (GameObject)Instantiate(dashEffect.gameObject, pivotHorizontalDashEffect.position, Quaternion.identity);
			
			if(direction.x > 0)
			{
				_transform.localScale = Vector3.one;
			}
			else if(direction.x < 0)
			{
				_transform.localScale = new Vector3(-1, 1, 1);
				g.transform.localScale = new Vector3(-1, 1, 1);
			}
			
			if(direction.y < 0)
			{
				g.transform.position = pivotDownDashEffect.position;
				g.transform.Rotate(Vector3.forward * 270);
			}
			
			jump = false;
			velocity = new Vector2(velocity.x, 0);
			
			onDash = true;
			currentTimeOnDash = 0;
			
			audioSource.PlayOneShot(dashClip);
			
			StartCoroutine(ToDash(direction));
		}
	}
	
	protected void TryJump()
	{
		if(footDetector.IsFree)
		{
			if(currentJump < jumpCount)
			{
				GameObject g = (GameObject)Instantiate(dashEffect.gameObject, pivotUpDashEffect.position, Quaternion.identity);
				g.transform.Rotate(Vector3.forward * 90);
				
				jump = true;
				currentJump ++;
			}
		}
		else
		{jump = true;}
		
		if(jump)
		{
			slowingJump = false;
			audioSource.PlayOneShot(jumpClip);
			
			currentHeightOnJump = 0;
			velocity = new Vector2(velocity.x, 0);
		}
	}
	
	private IEnumerator ToDash(Vector2 direction)
	{
		yield return new WaitForSeconds(0);
		
		currentTimeOnDash += Time.deltaTime;
		
		if((direction.x != 0 && !frontDetector.IsFree) || (direction.y < 0 && !footDetector.IsFree)
		   || currentTimeOnDash >= timeOnDash)
		{ onDash = false; }
		
		if(onDash)
		{
			if(direction.x > 0)
			{velocity = new Vector2(speedAxisX * 2, velocity.y);}
			else if(direction.x < 0)
			{velocity = new Vector2(-speedAxisX * 2, velocity.y);}
			
			if(direction.y > 0)
			{velocity = new Vector2(velocity.x, speedAxisX  * 2 * Time.deltaTime);}
			else if(direction.y < 0)
			{velocity = new Vector2(velocity.x, -speedAxisX  * 2 * Time.deltaTime);}
			
			StartCoroutine(ToDash(direction));
		}
	}
	
	protected void SpecialOnAir()
	{
		if(!specialAir)
		{
			iTween.ColorTo(backSpecial.gameObject, iTween.Hash("a", 0.8f, "time", 0.3f));
			hp = Mathf.Max(0, hp - 50);
			useGravity = false;
			velocity = Vector2.zero;
			
			if(!detectorSpecialAir.IsFree)
			{
				if(currentJump == jumpCount)
				{
					currentJump = jumpCount -1;
				}
			}
			
			audioSource.PlayOneShot(slashClip);
			StartCoroutine(PlaySlashSoundOnSpecialAir());
			
			animationUV.Stop();
			
			animationUV.Play("specialAir");
			
			GameObject g = (GameObject)Instantiate(specialAirEffect.gameObject, pivotSpecialAir.position, Quaternion.identity);
			
			tempAirEffect = g.GetComponent<ExplosionBehaviour>();
			
			if(transform.localScale.x < 0)
			{
				g.transform.localScale = new Vector3(-1, g.transform.localScale.y, g.transform.localScale.z);
			}
			
			g.transform.parent = transform;
			
			
			specialAir = true;
			
			StartCoroutine(WaitToCheckFinalAir());
		}
	}
	
	private IEnumerator PlaySlashSoundOnSpecialAir()
	{
		yield return new WaitForSeconds(0.1f);
		audioSource.PlayOneShot(slashClip);
		countSpecialAirEffect ++;
		
		if(countSpecialAirEffect < limitPlaySpecialAirEffect)
		{
			StartCoroutine(PlaySlashSoundOnSpecialAir());
		}
		else
		{
			countSpecialAirEffect = 0;
		}
	}
	
	private IEnumerator WaitToCheckFinalAir()
	{
		yield return new WaitForSeconds(0);
		
		if(tempAirEffect == null)
		{
			if(iTween.Count(backSpecial.gameObject) > 0)
			{
				iTween.Stop(backSpecial.gameObject);
				Destroy(backSpecial.GetComponent<iTween>());
			}
			
			backSpecial.renderer.sharedMaterial.color = new Color(backSpecial.renderer.sharedMaterial.color.r,
			backSpecial.renderer.sharedMaterial.color.g, backSpecial.renderer.sharedMaterial.color.b, 0);
			
			useGravity = true;
			specialAir = false;
		}
		else
		{
			if(!detectorSpecialAir.IsFree)
			{
				hitAnEnemy = true;
				
				for(int i = 0; i < detectorSpecialAir.GetObjects.Count; i++)
				{
					if(detectorSpecialAir.GetObjects[i].GetComponent<CharacterBehaviour>())
					{
						if(detectorSpecialAir.GetObjects[i].GetComponent<CharacterBehaviour>().Hit(hitSpecialAir, (_transform.localScale.x < 0), true))
						{
							detectorSpecialAir.GetObjects.RemoveAt(i);
							i--;
							diedAnEnemy ++;
						}
					}
				}
			}
			
			StartCoroutine(WaitToCheckFinalAir());
		}
	}
	
	protected void SpecialOnGround()
	{
		if(!specialShot)
		{
			iTween.ColorTo(backSpecial.gameObject, iTween.Hash("a", 0.8f, "time", 0.3f));
			hp = Mathf.Max(0, hp - 50);
			velocity = Vector2.zero;
			
			audioSource.PlayOneShot(shotClip);
			
			animationUV.Stop();
			
			animationUV.Play("shot");
			
			tempShotEffect = new ExplosionBehaviour[specialShotEffect.Length];
			
			for(int i = 0; i < specialShotEffect.Length; i++)
			{
				GameObject g = (GameObject)Instantiate(specialShotEffect[i].gameObject, pivotSpecialShot.position, Quaternion.identity);
				
				if(transform.localScale.x < 0)
				{
					g.transform.localScale = new Vector3(-1, g.transform.localScale.y, g.transform.localScale.z);
				}
				
				g.transform.parent = transform;
				
				tempShotEffect[i] = g.GetComponent<ExplosionBehaviour>();
			}
			
			specialShot = true;
			
			StartCoroutine(WaitToCheckFinalShot());
		}
	}
	
	private IEnumerator WaitToCheckFinalShot()
	{
		yield return new WaitForSeconds(0);
		
		bool allEffectsRemoved = true;
		
		foreach(ExplosionBehaviour e in tempShotEffect)
		{
			if(e != null)
			{
				allEffectsRemoved = false;
				break;
			}
		}
		
		if(allEffectsRemoved)
		{
			if(iTween.Count(backSpecial.gameObject) > 0)
			{
				iTween.Stop(backSpecial.gameObject);
				Destroy(backSpecial.GetComponent<iTween>());
			}
			
			backSpecial.renderer.sharedMaterial.color = new Color(backSpecial.renderer.sharedMaterial.color.r,
			backSpecial.renderer.sharedMaterial.color.g, backSpecial.renderer.sharedMaterial.color.b, 0);
			
			specialShot = false;
		}
		else
		{
			if(!detectorSpecialShot.IsFree)
			{
				hitAnEnemy = true;
				
				for(int i = 0; i < detectorSpecialShot.GetObjects.Count; i++)
				{
					if(detectorSpecialShot.GetObjects[i].GetComponent<CharacterBehaviour>())
					{
						if(detectorSpecialShot.GetObjects[i].GetComponent<CharacterBehaviour>().Hit(hitSpecialShot, false))
						{
							detectorSpecialShot.GetObjects.RemoveAt(i);
							i--;
							diedAnEnemy ++;
						}
					}
				}
			}
			
			StartCoroutine(WaitToCheckFinalShot());
		}
	}

	private void HitEffect()
	{
		currentTimeChange += Time.deltaTime;
		if(currentTimeChange >= timeChangeColor)
		{
			currentTimeChange = 0;
			
			currentCountChanges ++;
			if(currentCountChanges > countChangeColor)
			{
				currentCountChanges = 0;
				onHit = false;
			}
			else
			{
				changeColor = !changeColor;
				if(changeColor)
				{
					originalColor = animationUV.renderer.material.color;
					animationUV.renderer.material.color = Color.blue;
				}
				else
				{
					animationUV.renderer.material.color = originalColor;
				}
			}
		}
		
		if((backDetector && !backDetector.IsFree &&
		   ((transform.localScale.x > 0 && hitRightToLeft) || (transform.localScale.x < 0 && !hitRightToLeft) ) ) ||
		   (frontDetector && !frontDetector.IsFree &&
		   ((transform.localScale.x > 0 && !hitRightToLeft) || (transform.localScale.x < 0 && hitRightToLeft) ) )
			)
		{
			if(iTween.Count(gameObject) > 0)
			{
				iTween.Stop(gameObject);
				Destroy(gameObject.GetComponent<iTween>());
			}
		}
	}
	
	public bool Hit(int relativeHP, bool ofRightToLeft, bool showHitEffect)
	{
		if(!specialAir && !specialShot && (!haveDelayToHits || (haveDelayToHits && !onHit && enableHit)))
		{
			Hit(relativeHP, showHitEffect);
			
			if(hp > 0 && itsPushedOnHit)
			{
				hitRightToLeft = ofRightToLeft;
				
				if(ofRightToLeft && ((backDetector && backDetector.IsFree && transform.localScale.x > 0) ||
									 (frontDetector && frontDetector.IsFree && transform.localScale.x < 0)))
				{
					iTween.MoveBy(gameObject, Vector3.left * 150, 0.3f);
					//transform.Translate(Vector3.left * 20, Space.Self);
				}
				else if(!ofRightToLeft && ((backDetector && backDetector.IsFree && transform.localScale.x < 0) ||
									 (frontDetector && frontDetector.IsFree && transform.localScale.x > 0)))
				{
					iTween.MoveBy(gameObject, Vector3.right * 150, 0.3f);
					//transform.Translate(Vector3.right * 20, Space.Self);
				}
			}
			
			if(hp <= 0)
			{
				return true;
			}
		}
		
		return false;
	}
	
	public bool Hit(int relativeHP, bool showHitEffect)
	{
		if(!specialAir && !specialShot && (!haveDelayToHits || (haveDelayToHits && !onHit && enableHit)))
		{
			if(showHitEffect)
			{
				if(hitEffect)
				{
					GameObject g = (GameObject)Instantiate(hitEffect.gameObject, pivotHitEffect.position, Quaternion.identity);
					g.transform.Rotate(Vector3.forward * (Random.Range(0, 230)));
				}
			}
			
			hp -= relativeHP;
			
			enableHit = false;
			StartCoroutine(WaitToEnableHit());
			
			if(hp > 0)
			{
				onHit = true;
				
				if(animationUV != null)
				{
					animationUV.Play("hit");
				}
			}
			
			if(hp <= 0)
			{
				return true;
			}
		}
		
		return false;
	}
	
	private IEnumerator WaitToEnableHit()
	{
		yield return new WaitForSeconds(delayToEnableHit);
		enableHit = true;
	}
	
	private void UpdateAnimations()
	{
		if(footDetector && !footDetector.IsFree)
		{
			currentJump = 1;
		}
		
		if(!specialAir && !specialShot)
		{
			if(shooting || melee)
			{
				if(shooting)
				{
					if(animationUV.CanChangeAnimation)
					{shooting = false;}
				}
				else
				{
					if(animationUV.CanChangeAnimation)
					{melee = false;}
				}
			}
			else
			{
				if(velocity.y > 0)
				{animationUV.Play("jump");}// + currentJump.ToString());}
				else
				{
					if((!onDash && velocity.y < 0))
					{animationUV.Play("fall");}
					else if(onDash)
					{
						if(directionDash.x != 0)
						{animationUV.Play("horizontalDash");}
						else
						{animationUV.Play("verticalDash");}
					}
				}
				
				if(!onDash)
				{
					if(!jump && footDetector != null && !footDetector.IsFree)
					{
						if(velocity.x.Equals(0))
						{animationUV.Play("idle");}
						else
						{animationUV.Play("walk");}
					}
				}
			}
		}
	}
	
	private void UpdateJump()
	{
		if(useGravity)
		{
			if(jump && currentHeightOnJump < maxHeightOnJump/4.0f)
			{
				velocity += Vector2.up * 100 * Time.deltaTime;
				
				if(slowingJump)
				{
					velocity = new Vector2(velocity.x, velocity.y/2);
				}
				
				currentHeightOnJump += velocity.y;
			}
			else if(!onDash)// || (onDash && jump && directionDash.y == 0))
			{
				if(footDetector.IsFree)
				{
					velocity -= Vector2.up * 35 * Time.deltaTime;
					if(velocity.y < -50)
					{
						velocity = new Vector2(velocity.x, -50);
					}
					
					if(slowingJump)// && velocity.y < 0)
					{
						velocity = new Vector2(velocity.x, velocity.y / 2);
					}
					
					if(velocity.y < 0)
					{ jump = false; }
				}
				else
				{
					jump = false;
					
					if(footDetector.GetColliderMoreNear)
					{
						_transform.position = new Vector3(_transform.position.x, footDetector.GetColliderMoreNear.bounds.max.y, _transform.position.z);
					}
					
					if(velocity.y != 0)
					{
						Instantiate(littleDust.gameObject, pivotDust.position, Quaternion.identity);
						GameObject g = (GameObject)Instantiate(littleDust.gameObject, pivotDust.position, Quaternion.identity);
						g.transform.localScale = new Vector3(-1, g.transform.localScale.y, g.transform.localScale.z);
					}
					
					velocity = new Vector2(velocity.x, 0);
				}
			}
		}
	}
	
	private void UpdateDustOnGround()
	{
		if(littleDust)
		{
			if(velocity.x == 0)
			{
				oldVelocityX = 0;
			}
			else if(oldVelocityX != velocity.x)
			{
				if(footDetector && !footDetector.IsFree)
				{
					GameObject g = (GameObject)Instantiate(littleDust.gameObject, pivotDust.position, Quaternion.identity);
					
					if(velocity.x > 0)
					{ g.transform.localScale = new Vector3(-1, g.transform.localScale.y, g.transform.localScale.z); }
					
					oldVelocityX = velocity.x;
				}
			}
		}
	}
}
